#include "hi_ext_util.h"
#include "plug_talk.h"
#include "plug_media_ao.h"

#include "libavutil/opt.h"
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* End of #ifdef __cplusplus */

#define AVBUFFSIZE (5 * 1024)

typedef struct tagPLUG_TALK_CTX
{
    HI_BOOL bInit;
    HI_BOOL mStart;
    HI_S32 talkInterrupt;
    pthread_t talkTaskId;
    pthread_mutex_t talkMutex;
    AVFormatContext* pstTalkCtx;
} PLUG_TALK_CTX;

static PLUG_TALK_CTX s_stTalkCtx = {0};

static HI_S32 interrupt_cb(HI_VOID *ctx)
{
    //LOGE("--- talkInterrupt = %d ---\n", s_stTalkCtx.talkInterrupt);
    return s_stTalkCtx.talkInterrupt == 1 ? 1 : 0;//中断信号
}

static HI_VOID setAvInterrupt(HI_BOOL vaule)
{
    LOGI("set talkInterrupt %d\n", vaule);
    vaule == HI_TRUE ? (s_stTalkCtx.talkInterrupt = 1):(s_stTalkCtx.talkInterrupt = 0);
}

static HI_VOID adecTask(HI_VOID *param)
{
    HI_S32 ret;
    HI_U16 u16len = 0;
    HI_U8 *tmpbuf = HI_NULL;
    PLUG_AO_STREAM_S stTalkData;
    memset(&stTalkData, 0x0, sizeof(PLUG_AO_STREAM_S));
    
    AVPacket *pkt = av_packet_alloc();
    tmpbuf = malloc(AVBUFFSIZE);
    while(s_stTalkCtx.mStart == HI_TRUE)
    {
        pthread_mutex_lock(&s_stTalkCtx.talkMutex);
        ret = av_read_frame(s_stTalkCtx.pstTalkCtx, pkt);
        if(ret < 0)
        {
            LOGE("error:%d\n", ret);
            if (ret == AVERROR(EAGAIN))
            {
                usleep(50 * 1000);
                continue;    
            }
            pthread_mutex_unlock(&s_stTalkCtx.talkMutex);
            break;
        }
                
        if(pkt->size > 0)
        {
            stTalkData.u64TimeStamp = pkt->pts;
            stTalkData.pStream = pkt->data;
            stTalkData.u32Len = pkt->size;

            //LOGI("talk data len = %d\n", stTalkData.u32Len);
                        
            ret = PLUG_MEDIA_AO_TalkSound(&stTalkData);
            if(ret != HI_SUCCESS)
            {
                LOGE("PLUG_MEDIA_AO_TalkSound failed.\n");
            }
        }
        av_packet_unref(pkt);
    }    
    LOGE("exit adecTask pthread \n");
    av_packet_free(&pkt);
    free(tmpbuf);
    tmpbuf = HI_NULL;
    pthread_mutex_unlock(&s_stTalkCtx.talkMutex);
    return;
}

static PAYLOAD_TYPE_E ff2hi_etype(enum AVCodecID codeId)
{
    switch (codeId)
    {
    case AV_CODEC_ID_PCM_S16LE:
        return PT_G711A;
    case AV_CODEC_ID_PCM_U8:
        return PT_PCMU;
    case AV_CODEC_ID_PCM_ALAW:
        return PT_G711A;
    case AV_CODEC_ID_PCM_MULAW:
        return PT_G711U;
    case AV_CODEC_ID_MPEG2TS:
        return PT_MPEG2TS;
    case AV_CODEC_ID_H263:
        return PT_H263;
    case AV_CODEC_ID_AAC:
        return PT_AAC;
    case AV_CODEC_ID_MP3:
        return PT_MP3;
    case AV_CODEC_ID_H264:
        return PT_H264;
    case AV_CODEC_ID_MPEG4:
        return PT_MP4VIDEO;
    case AV_CODEC_ID_HEVC:
        return PT_H265;
    default:
    {
        LOGE("vaild codeID:%d\n", codeId);
        return PT_BUTT;
    }
    }
    return PT_BUTT;
}

HI_S32 PLUG_TALK_Init(HI_CHAR* talkUrl)
{
    HI_S32 s32Ret = HI_SUCCESS;
    AVDictionary *opts = NULL;
    PAYLOAD_TYPE_E etype = PT_BUTT;

    if (s_stTalkCtx.mStart == HI_TRUE)
    {
        LOGE("talk has start\n");
        return HI_SUCCESS;
    }
    pthread_mutex_init(&s_stTalkCtx.talkMutex, NULL);
    
    //对讲注入
    s_stTalkCtx.pstTalkCtx = avformat_alloc_context();
    s_stTalkCtx.pstTalkCtx->interrupt_callback.callback = interrupt_cb;
    s_stTalkCtx.pstTalkCtx->interrupt_callback.opaque = s_stTalkCtx.pstTalkCtx;

    av_dict_set(&opts, "stimeout", "80000000", 0);    //设置超时断开连接时间，单位微秒
    av_dict_set(&opts, "max_delay", "500", 0);
    av_dict_set(&opts, "rtsp_transport", "tcp", 0);   //set tcp
    av_dict_set(&opts, "sample_rate", "8000", 0);     //设定采样率为8000
    av_dict_set(&opts, "channels", "1", 0);           //设定声道为单声道
    av_dict_set(&opts, "rw_timeout", "8000000", 0);    

    //重新avformat_open_input，容易产生：DumpErrorCodes  - 错误代码：AVERROR_EXIT = -1414092869 
    AVInputFormat *inf = av_find_input_format("alaw");//设定输入的音频格式是alaw
    av_register_all();
    if ((s32Ret = avformat_open_input(&s_stTalkCtx.pstTalkCtx, talkUrl, inf, &opts)) != 0)
    {
        if (!(s_stTalkCtx.pstTalkCtx))
        {
            avformat_free_context(s_stTalkCtx.pstTalkCtx);
        }
        LOGE("avformat_open_input failed![%d]\n", s32Ret);
        return HI_FAILURE;
    }
    etype = ff2hi_etype(s_stTalkCtx.pstTalkCtx->streams[0]->codecpar->codec_id);
    LOGI("etype:[%d]\n", etype);
    LOGI("sample_rate:[%d]\n", s_stTalkCtx.pstTalkCtx->streams[0]->codecpar->sample_rate);
    LOGI("channel_layout:[%d]\n", s_stTalkCtx.pstTalkCtx->streams[0]->codecpar->channel_layout);

    s32Ret = PLUG_MEDIA_AO_Deinit();
    if (HI_SUCCESS != s32Ret)
    {
        LOGE("PLUG_MEDIA_AO_Deinit failed!\n");
    }
    s32Ret = PLUG_MEDIA_AO_Init(PT_G711A);
    if (HI_SUCCESS != s32Ret)
    {
        LOGE("PLUG_MEDIA_AO_Init failed!\n");
    }
    s32Ret = pthread_create(&s_stTalkCtx.talkTaskId, HI_NULL, adecTask, HI_NULL);
    if (HI_SUCCESS != s32Ret)
    {
        LOGE("pthread create decTask failed!\n");
    }
    
    PLUG_MEDIA_AO_SetSysSound(HI_FALSE);
    
    s_stTalkCtx.bInit = HI_TRUE;
    s_stTalkCtx.mStart = HI_TRUE;
    return HI_SUCCESS;
}

HI_S32 PLUG_TALK_Deinit(HI_VOID)
{
    HI_S32 s32Ret = HI_SUCCESS;
    if (s_stTalkCtx.mStart == HI_FALSE)
    {
        LOGE("talk not start");
        return HI_SUCCESS;
    }
    //setAvInterrupt(HI_TRUE);
    PLUG_MEDIA_AO_SetSysSound(HI_TRUE);
        
    if(s_stTalkCtx.talkTaskId != 0){
        pthread_kill(s_stTalkCtx.talkTaskId, 0);
        pthread_cancel(s_stTalkCtx.talkTaskId);
        s_stTalkCtx.talkTaskId = 0;
    }
    
    avformat_close_input(&s_stTalkCtx.pstTalkCtx);
    avformat_free_context(s_stTalkCtx.pstTalkCtx);
    
    s32Ret = PLUG_MEDIA_AO_Deinit();
    if (HI_SUCCESS != s32Ret)
    {
        LOGE("PLUG_MEDIA_AO_Deinit failed!\n");
    }
    s32Ret = PLUG_MEDIA_AO_Init(PT_AAC);
    if (HI_SUCCESS != s32Ret)
    {
        LOGE("PLUG_MEDIA_AO_Deinit failed!\n");
    }
    pthread_mutex_destroy(&s_stTalkCtx.talkMutex);
    
    s_stTalkCtx.bInit = HI_FALSE;
    s_stTalkCtx.mStart = HI_FALSE;
    
    return HI_SUCCESS;
}


#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus */

